﻿using System;
using System.Collections.Generic;
using System.Data;
using Dapper;
using Isaac.Joy.Ormapping.Contract;

namespace Isaac.Joy.Ormapping.Dapper
{
    public class Database<TConnection> : IDatabase where TConnection : IDbConnection, new()
    {
        protected string ConnectionString { get; private set; }

        public Database(string cnstr)
        {
            ConnectionString = cnstr;
        }

        private TConnection CreateConnection()
        {
            var cn = new TConnection { ConnectionString = ConnectionString };
            cn.Open();
            return cn;
        }

        public int Execute(string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null,
            CommandType? commandType = null)
        {
            using (var cn = CreateConnection())
            {
                return cn.Execute(sql, param, transaction, commandTimeout, commandType);
            }
        }

        public IDataReader ExecuteReader(string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null,
            CommandType? commandType = null)
        {
            using (var cn = CreateConnection())
            {
                return cn.ExecuteReader(sql, param, transaction, commandTimeout, commandType);
            }
        }

        public object ExecuteScalar(string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null,
            CommandType? commandType = null)
        {
            using (var cn = CreateConnection())
            {
                return cn.ExecuteScalar(sql, param, transaction, commandTimeout, commandType);
            }
        }

        public T ExecuteScalar<T>(string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null,
            CommandType? commandType = null)
        {
            using (var cn = CreateConnection())
            {
                return cn.ExecuteScalar<T>(sql, param, transaction, commandTimeout, commandType);
            }
        }

        public IEnumerable<T> Query<T>(string sql, object param = null, IDbTransaction transaction = null, bool buffered = true,
            int? commandTimeout = null, CommandType? commandType = null)
        {
            using (var cn = CreateConnection())
            {
                return cn.Query<T>(sql, param, transaction, buffered, commandTimeout, commandType);
            }
        }

        public IEnumerable<TReturn> Query<TReturn>(string sql, Type[] types, Func<object[], TReturn> map, dynamic param = null, IDbTransaction transaction = null,
            bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null)
        {
            using (var cn = CreateConnection())
            {
                return SqlMapper.Query(cn, sql, types, map, param, transaction, buffered, splitOn, commandTimeout, commandType);
            }
        }

        public IEnumerable<dynamic> Query(string sql, object param = null, IDbTransaction transaction = null, bool buffered = true,
            int? commandTimeout = null, CommandType? commandType = null)
        {
            using (var cn = CreateConnection())
            {
                return cn.Query<dynamic>(sql, param, transaction, buffered, commandTimeout, commandType);
            }
        }

        public IEnumerable<object> Query(Type type, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true,
            int? commandTimeout = null, CommandType? commandType = null)
        {
            using (var cn = CreateConnection())
            {
                return cn.Query<object>(sql, param, transaction, buffered, commandTimeout, commandType);
            }
        }

        public IEnumerable<TReturn> Query<TFirst, TSecond, TReturn>(string sql, Func<TFirst, TSecond, TReturn> map, object param = null, IDbTransaction transaction = null,
            bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null)
        {
            using (var cn = CreateConnection())
            {
                return cn.Query(sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType);
            }
        }

        public IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TReturn>(string sql, Func<TFirst, TSecond, TThird, TReturn> map, object param = null,
            IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null,
            CommandType? commandType = null)
        {
            using (var cn = CreateConnection())
            {
                return cn.Query(sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType);
            }
        }

        public IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TReturn>(string sql, Func<TFirst, TSecond, TThird, TFourth, TReturn> map, object param = null,
            IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null,
            CommandType? commandType = null)
        {
            using (var cn = CreateConnection())
            {
                return cn.Query(sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType);
            }
        }

        public IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TFifth, TReturn>(string sql, Func<TFirst, TSecond, TThird, TFourth, TFifth, TReturn> map, object param = null,
            IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null,
            CommandType? commandType = null)
        {
            using (var cn = CreateConnection())
            {
                return cn.Query(sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType);
            }
        }

        public IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TReturn>(string sql, Func<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TReturn> map, object param = null,
            IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null,
            CommandType? commandType = null)
        {
            using (var cn = CreateConnection())
            {
                return cn.Query(sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType);
            }
        }

        public IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(string sql, Func<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn> map,
            object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id",
            int? commandTimeout = null, CommandType? commandType = null)
        {
            using (var cn = CreateConnection())
            {
                return cn.Query(sql, map, param, transaction, buffered, splitOn, commandTimeout, commandType);
            }
        }
    }
}
